<template>
    <div style="width: 300px">
        总进度：
        <el-progress :text-inside="true" :stroke-width="26" :percentage="totalPercent" />切片进度：
        <!-- <div v-for="item in fileObj.chunkList" :key="item">
            <span>{{ item.chunkName }}：</span>
            <el-progress :percentage="item.percent"></el-progress>
        </div>+-->
    </div>
    <input type="file" @change="handleFileChange" />
    <el-button type="primary" @click="upload">uploadFile</el-button>
    <el-button @click="pauseUpload">暂停</el-button>
    <el-button @click="keepUpload">续传</el-button>
</template>

<script setup>
import { computed, reactive, watch } from "vue-demi";
import axios from "axios";

let CancelToken = axios.CancelToken;
let source = CancelToken.source();

// 封装axios请求方法
function axiosRequest({
    url,
    method = "post",
    data,
    headers = {},
    onUploadProgress = (e) => e, // 进度回调
}) {
    return new Promise((resolve, reject) => {
        axios[method](url, data, {
            headers,
            onUploadProgress, // 传入监听进度回调
            cancelToken: source.token
        })
            .then((res) => {
                resolve(res);
            })
            .catch((err) => {
                reject(err);
            });
    });
}

// 定义变量接收上传的文件
const fileObj = reactive({ file: null })

// 点击选择文件
const handleFileChange = (e) => {
    const [file] = e.target.files
    if (!file) return
    fileObj.file = file
}

// 秒传，验证
const verifyUpload = async (fileName) => {
    const { data } = await axiosRequest({
        url: "http://localhost:3001/verify",
        headers: {
            "content-type": "application/json",
        },
        data: JSON.stringify({
            fileName,
        }),
    });
    return data
}

// 点击上传
const upload = async () => {
    console.log('upload');
    if (!fileObj.file) return

    // 请求之前进行验证，如果服务器存在就直接显示上传成功
    const { shouldUpload } = await verifyUpload(
        fileObj.file.name,
    );
    if (!shouldUpload) {
        totalPercent.value = 100
        alert("秒传：上传成功");
        return;
    }


    const chunkList = chunks(fileObj.file)
    fileObj.chunkList = chunkList.map(({ file }, index) => ({
        file,
        size: file.size,
        percent: 0,
        chunkName: `${fileObj.file.name}-${index}`,
        fileName: fileObj.file.name,
        index,
    }));
    console.log(fileObj);
    // 上传
    uploadChunks(fileObj.chunkList)
}
const uploadChunks = async (data) => {
    // let fileData
    // if(!data){
    //     fileData = fileObj
    // }else{
    //     fileData = data
    // }

    const requestList = data
        .map(({ file, fileName, index, chunkName }) => {
            const formData = new FormData();
            formData.append("file", file);
            formData.append("fileName", fileName);
            formData.append("chunkName", chunkName);
            return { formData, index };
        })
        .map(({ formData, index }) =>
            axiosRequest({
                url: "http://localhost:3001/upload",
                data: formData,
                onUploadProgress: createProgressHandler(
                    fileObj.chunkList[index]
                ), // 传入监听上传进度回调
            })
        );
    await Promise.all(requestList); // 使用Promise.all进行请求
    // 上传完毕之后，发起合并请求
    mergeChunks()
}
const createProgressHandler = (item) => {
    return (e) => {
        // 设置每一个切片的进度百分比
        item.percent = parseInt(String((e.loaded / e.total) * 100));
    };
}
// 发起文件合并请求
const mergeChunks = (size = 100 * 1024 * 1024) => {
    axiosRequest({
        url: "http://localhost:3001/merge",
        headers: {
            "content-type": "application/json",
        },
        data: JSON.stringify({
            size,
            fileName: fileObj.file.name
        }),
    }).then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err);
    });
}
// 文件切片
const chunks = (file, size = 100 * 1024 * 1024) => {
    const chunkList = []
    let current = 0
    while (current < file.size) {
        chunkList.push({ file: file.slice(current, current + size) })
        current = current + size
    }
    return chunkList

}

// 暂停上传
const pauseUpload = () => {
    source.cancel("中断上传!");
    source = CancelToken.source(); // 重置source，确保能续传
}
// 继续上传
const keepUpload = async () => {
    const { uploadedList } = await verifyUpload(
        fileObj.file.name
    );
    if (!uploadedList.length) {
        console.log('上传中，请稍等~');
    }
    // 处理已经上传成功的数组列表
    let successArr = []
    uploadedList.forEach(item => {
        let temArr = item.split('-')
        successArr.push(Number(temArr[temArr.length - 1]))
    });

    let result = []
    for (let i = 0; i < fileObj.chunkList.length; i++) {
        // 上传过就跳过
        if (successArr.indexOf(fileObj.chunkList[i].index) !== -1) {
            continue;
        }
        result.push(fileObj.chunkList[i])
    }


    uploadChunks(result);
}

// 上传进度计算
let totalPercent = computed(() => {
    if (!fileObj.file || !fileObj.chunkList) return 0
    const loaded = fileObj.chunkList
        .map(({ size, percent }) => size * percent)
        .reduce((pre, next) => pre + next);
    return parseInt((loaded / fileObj.file.size).toFixed(2));
})



</script>

<style>
</style>